package com.meng.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.*;


/**
 * 线程池工具类
 *
 * @author MENG
 * @version 2018/3/21
 * @see
 */
public class ThreadPoolUtil
{
    static Logger logger = LoggerFactory.getLogger(ThreadPoolUtil.class);

    private static ExecutorService getCachedThreadPool()
    {
        return LazyCachedThreadPool.instance;
    }

    public static ExecutorService getWriteDataToRedisFixedThreadPool()
    {
        return WriteRedisFixedThreadPool.instance;
    }

    public static ScheduledExecutorService getSyncRedisDataToMysqlSingleScheduledThreadPool()
    {
        return SyncRedisDataToMysqlSingleScheduledThreadPool.instance;
    }

    /**
     * 这个实例会根据需要，在线程可用时，重用之前构造好的池中线程
     * 。
     * 这个线程池在执行 大量短生命周期的异步任务时（many short-lived asynchronous task），可以显著提高程序性能
     *
     */
    private static class LazyCachedThreadPool
    {
        //CachedThreadPool
        private static final ExecutorService instance = new ThreadPoolExecutor(0, Integer.MAX_VALUE,

            30L, TimeUnit.SECONDS,

            new SynchronousQueue<Runnable>()

        );



    }


    /**
     * 实例会复用 固定数量的线程 处理一个 共享的无边界队列
     *
     * 最多有 8 个线程会处于活动状态执行任务
     *
     * Runtime.getRuntime().availableProcessors() = cpu核数
     *
     * IO密集型=2Ncpu
     *
     * 计算密集型=Ncpu+1
     *
     * 数据写入Redis 线程池
     */
    private static class WriteRedisFixedThreadPool
    {
        //FixedThreadPool
        private static final ExecutorService instance = new ThreadPoolExecutor(8, 8,

            0L, TimeUnit.MILLISECONDS,

            new LinkedBlockingDeque<>()
        ){

            protected void afterExecute(Runnable r, Throwable t)
            {
                super.afterExecute(r, t);

                printException(r);
            }
        };
    }

    /**
     * 定时工作线程池
     *
     * redis数据同步mysql 并写入文件 线程池
     */
    private static class SyncRedisDataToMysqlSingleScheduledThreadPool
    {
        //FixedThreadPool
        private static final ScheduledExecutorService instance = Executors.newSingleThreadScheduledExecutor();
    }

    /**
     * 多线程打印异常
     *
     * @param r
     */
    private static void printException(Runnable r)
    {
        if (r instanceof Future<?>)
        {
            try {

                Future<?> future = (Future<?>) r;

                if (future.isDone())
                    future.get();

            }
            catch (ExecutionException | InterruptedException ee)
            {
                logger.error("数据写入Redis执行异常!!!", ee);
            }
        }
    }
}
